{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "模型构建"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from mxnet import nd\n",
    "from mxnet.gluon import nn\n",
    "class MLP(nn.Block):\n",
    "    def __init__(self, **kwarges):\n",
    "        #调用MLP父类Block的构建函数来进行必要的初始化\n",
    "        super(MLP, self).__init__(**kwarges)\n",
    "        self.hidden = nn.Dense(256, activation='relu')\n",
    "        self.output = nn.Dense(10)\n",
    "    # 定义模型的向前计算，即如何根据输入X计算反向所需的模型输出\n",
    "    def forward(self, x):\n",
    "        return self.output(self.hidden(x))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\n",
       "[[ 0.09543003  0.04614332 -0.00286653 -0.07790346 -0.05130243  0.02942039\n",
       "   0.08696645 -0.0190793  -0.04122177  0.05088576]\n",
       " [ 0.0769287   0.03099705  0.00856576 -0.04467198 -0.0692684   0.09132432\n",
       "   0.06786594 -0.06187843 -0.03436674  0.04234695]]\n",
       "<NDArray 2x10 @cpu(0)>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X = nd.random.uniform(shape=(2, 20))\n",
    "net = MLP()\n",
    "net.initialize()\n",
    "net(X)"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "Sequential类继续自Block类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MySequential(nn.Block):\n",
    "    def __init__(self, **kwargs):\n",
    "        super(MySequential, self).__init__(**kwargs)\n",
    "        \n",
    "    def add(self, block):\n",
    "        self._children[block.name] = block\n",
    "    def forward(self, x):\n",
    "        for block in self._children.values():\n",
    "            x = block(x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\n",
       "[[ 0.0036223   0.00633331  0.03201144 -0.01369375  0.10336448 -0.03508019\n",
       "  -0.00032164 -0.01676024  0.06978628  0.01303308]\n",
       " [ 0.03871716  0.02608212  0.03544959 -0.02521311  0.11005434 -0.01430662\n",
       "  -0.03052465 -0.03852826  0.06321152  0.0038594 ]]\n",
       "<NDArray 2x10 @cpu(0)>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net = MySequential()\n",
    "net.add(nn.Dense(256, activation='relu'))\n",
    "net.add(nn.Dense(10))\n",
    "net.initialize()\n",
    "net(X)"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "构建复杂的模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class FancyMLP(nn.Block):\n",
    "    def __init__(self, **kwargs):\n",
    "        super(FancyMLP, self).__init__(**kwargs)\n",
    "        # 使用get_constant创建的随机权重参数不会在训练中被迭代（即常数参数）\n",
    "        self.rand_weight = self.params.get_constant(\n",
    "            'rand_weight', nd.random.uniform(shape=(20, 20)))\n",
    "        self.dense = nn.Dense(20, activation='relu')\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.dense(x)\n",
    "        # 使用创建的常数参数，以及NDArray的relu函数和dot函数\n",
    "        x = nd.relu(nd.dot(x, self.rand_weight.data()) + 1)\n",
    "        # 复用全连接层。等价于两个全连接层共享参数\n",
    "        x = self.dense(x)\n",
    "        # 控制流，这里我们需要调用asscalar函数来返回标量进行比较\n",
    "        while x.norm().asscalar() > 1:\n",
    "            x /= 2\n",
    "        if x.norm().asscalar() < 0.8:\n",
    "            x *= 10\n",
    "        return x.sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\n",
       "[18.571953]\n",
       "<NDArray 1 @cpu(0)>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net = FancyMLP()\n",
    "net.initialize()\n",
    "net(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\n",
       "[24.866209]\n",
       "<NDArray 1 @cpu(0)>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class NestMLP(nn.Block):\n",
    "    def __init__(self, **kwargs):\n",
    "        super(NestMLP, self).__init__(**kwargs)\n",
    "        self.net = nn.Sequential()\n",
    "        self.net.add(nn.Dense(64, activation='relu'),\n",
    "                    nn.Dense(32, activation='relu'))\n",
    "        self.dense = nn.Dense(16, activation='relu')\n",
    "    \n",
    "    def forward(self, x):\n",
    "        return self.dense(self.net(x))\n",
    "\n",
    "net = nn.Sequential()\n",
    "net.add(NestMLP(), nn.Dense(20), FancyMLP())\n",
    "\n",
    "net.initialize()\n",
    "net(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
